
#ifndef SPI11_FLASH_H
#define SPI11_FLASH_H

#include "userdefine.h"
#include "BAT32G137.h"
#include "sci.h"
#include "dma.h"

#define SPI11_BUFFER_EMPTY

/**************************************************************************
* SPI Data and Status Register
**************************************************************************/
#define SPI_WRDR        (SCI0->SIO11)
#define SPI_RDDR        (SCI0->SIO11)
#define SPI_BUSY        (SCI0->SSR03 & _0040_SCI_UNDER_EXECUTE)
#define SPI_RRDY        (SCI0->SSR03 & _0020_SCI_VALID_STORED)
#define SPI_FLASH_CS_CLR()  SS11_PORT_CLR()
#define SPI_FLASH_CS_SET()  SS11_PORT_SET()

/**************************************************************************
* SPI NOR Flash Instruction defination
**************************************************************************/
#define BYTE_FIELD(value, byte) ((adr & (0xFF << 8 * byte )) >> 8 * byte)
#define ENABLE_RESET        (0x66U)     // Enable Reset Instruction
#define RESET_DEVICE        (0x99U)     // Reset Device Instruction
#define READ_STATUS1        (0x05U)     // Read Status Register-1 Instruction
#define READ_STATUS2        (0x35U)     // Read Status Register-2 Instruction
#define WRITE_STATUS1       (0x01U)     // Write Status Register-1 Instruction
#define WRITE_STATUS2       (0x31U)     // Write Status Register-2 Instruction
#define WRITE_ENABLE        (0x06U)     // Write Enable Instruction
#define WRITE_DISABLE       (0x04U)     // Write Disable Instruction
#define READ_DATA           (0x03U)     // Read Data Instruction
#define FAST_READ           (0x0BU)     // Fast Read Instruction
#define SECTOR_ERASE        (0x20U)     // 4KB Sector Erase Instruction
#define BLOCK_ERASE         (0x52U)     // 16KB Block Erase Instruction
#define CHIP_ERASE          (0x60U)     // Chip Erase Instruction
#define PAGE_WRITE          (0x02U)     // Page Program Instruction

/**************************************************************************
* Bit Fields defination
**************************************************************************/
// SPI Nor Flash Status Register-1
#define BUSY_Pos        (0x00U)
#define BUSY_Msk        (0x01U)
#define WEL_Pos         (0x01U)
#define WEL_Msk         (0x02U)
#define BP_Pos          (0x04U)
#define BP_Msk          (0x30U)
#define TB_Pos          (0x06U)
#define TB_Msk          (0x40U)
#define BPL_Pos         (0x07U)
#define BPS_Msk         (0x80U)
// SPI Nor Flash Status Register-2
#define QE_Pos          (0x01U)
#define QE_Msk          (0x02U)

/**************************************************************************
* Typedef defination
**************************************************************************/
typedef enum
{
    STATUS_REG1 = 1,
    STATUS_REG2 = 2
} status_t;

/**************************************************************************
* Global variables
**************************************************************************/
static volatile uint8_t sdr_prescale;

/**************************************************************************
* Global functions
**************************************************************************/
__STATIC_INLINE void LOOP_WAIT(uint32_t n)
{
    while(n--)
    {
        __NOP();
    }
}

__STATIC_INLINE void SPI_SPEED(uint8_t n) 
{
    SCI0->ST0 |= _0008_SCI_CH3_START_TRG_ON;
    SCI0->SDR03 = n << 9;   // fMCK/(1+n)x2
    sdr_prescale = n;
    SCI0->SS0 |= _0008_SCI_CH3_START_TRG_ON;
}

__STATIC_INLINE void SPI_INIT(spi_mode_t mode)
{
    uint8_t dap, ckp;
    dap = ~mode & 0x01;
    ckp = (~mode & 0x02) >> 1;
    CGC->PER0 |= CGC_PER0_SCI0EN_Msk;
    SCI0->ST0 |= _0008_SCI_CH3_STOP_TRG_ON;
    SCI0->SPS0 &= ~SCI0_SPS0_PRS01_Msk;
    SCI0->SPS0 |= (0 << SCI0_SPS0_PRS01_Pos);
    SCI0->SIR03 = _0004_SCI_SIRMN_FECTMN | _0002_SCI_SIRMN_PECTMN | _0001_SCI_SIRMN_OVCTMN;
    SCI0->SMR03 = _0020_SMRMN_DEFAULT_VALUE | _8000_SCI_CLOCK_SELECT_CK01 | _0000_SCI_CLOCK_MODE_CKS |
                  _0000_SCI_TRIGGER_SOFTWARE | _0000_SCI_MODE_SPI | _0000_SCI_TRANSFER_END;
    SCI0->SCR03 = _0004_SCRMN_DEFAULT_VALUE | _C000_SCI_RECEPTION_TRANSMISSION | dap << 13 | ckp << 12 | _0000_SCI_INTSRE_MASK |
                  _0000_SCI_PARITY_NONE | _0000_SCI_MSB | _0000_SCI_STOP_NONE | _0003_SCI_LENGTH_8;
    SPI_SPEED(3);
    /* Set output enable */
    if ((mode == SPI_MODE_0) || (mode == SPI_MODE_1))
    {
        SCI0->SO0 &= ~_0800_SCI_CH3_CLOCK_OUTPUT_1;
    }
    if ((mode == SPI_MODE_2) || (mode == SPI_MODE_3))
    {
        SCI0->SO0 |= _0800_SCI_CH3_CLOCK_OUTPUT_1;
    }
    SCI0->SOE0 |= _0008_SCI_CH3_OUTPUT_ENABLE;
    SCI0->SS0 |= _0008_SCI_CH3_START_TRG_ON;

    /* Set SSn pin */
    SS11_PORT_SETTING();
    /* Set SCLK11 pin */
    SCLKO11_PORT_SETTING();
    /* Set SDI11 pin */
    SDI11_PORT_SETTING();
    /* Set SDO11 pin */
    SDO11_PORT_SETTING();
}

__STATIC_INLINE void SPI_CPU_WRITE(uint8_t data) 
{
    volatile uint8_t dummy;
    SCI0->SCR03 |= (1<<13);     // DAP = 1
    SPI_WRDR = data;    
    while(SPI_BUSY);
    dummy = SPI_RDDR;
}

__STATIC_INLINE uint8_t SPI_CPU_READ(void)  
{
    volatile uint8_t tmp;
    SCI0->SCR03 &= ~(1<<13);    // DAP = 0
    SPI_WRDR = 0xFFU;
    while(SPI_RRDY == 0);
    tmp = SPI_RDDR;
    return (tmp);
}

__STATIC_INLINE void SPI_DMA_WRITE(uint8_t *const tx_buf, uint16_t tx_num) 
{
    SCI0->SCR03 |= (1<<13);     // DAP = 1
    SCI0->SIR03 = _0004_SCI_SIRMN_FECTMN | _0002_SCI_SIRMN_PECTMN | _0001_SCI_SIRMN_OVCTMN;
    SCI0->SCR03 &= ~_C000_SCI_RECEPTION_TRANSMISSION;
    SCI0->SCR03 |= _8000_SCI_TRANSMISSION;

    /* write transfer data with DMA */
    DMAVEC->VEC[DMA_VECTOR_SPI11] = CTRL_DATA_SPI11;
    DMAVEC->CTRL[CTRL_DATA_SPI11].DMACR = (0 << CTRL_DMACR_SZ_Pos) | (0 << CTRL_DMACR_CHNE_Pos) |
                                          (0 << CTRL_DMACR_DAMOD_Pos) | (1 << CTRL_DMACR_SAMOD_Pos) |
                                          (0 << CTRL_DMACR_MODE_Pos);
    DMAVEC->CTRL[CTRL_DATA_SPI11].DMBLS = 1;
    DMAVEC->CTRL[CTRL_DATA_SPI11].DMACT = tx_num -1;
    DMAVEC->CTRL[CTRL_DATA_SPI11].DMRLD = tx_num -1;
    DMAVEC->CTRL[CTRL_DATA_SPI11].DMSAR = (uint32_t)(tx_buf + 1);
    DMAVEC->CTRL[CTRL_DATA_SPI11].DMDAR = (uint32_t)&SPI_WRDR;

    /* init DMA registers */
    INT->IF[SPI11_IRQn].IFL = 0;
    CGC->PER1 |= CGC_PER1_DMAEN_Msk;
    DMA->DMABAR = DMAVEC_BASE;
    DMA->DMAEN1 |= (1 << DMA_VECTOR_SPI11 % 8);
    SPI_WRDR = tx_buf[0];

    /* waiting DMA transfer end */
    while(INT->IF[SPI11_IRQn].IFL == 0x00);
    while(SPI_BUSY);
    INT->IF[SPI11_IRQn].IFL = 0;
    SCI0->SCR03 |=  _C000_SCI_RECEPTION_TRANSMISSION;
}

__STATIC_INLINE void SPI_DMA_READ(uint8_t *const rx_buf, uint16_t rx_num)   
{
    volatile uint8_t dummy = 0xFFU;
    SCI0->SCR03 &= ~(1<<13);    // DAP = 0
    SCI0->SIR03 = _0004_SCI_SIRMN_FECTMN | _0002_SCI_SIRMN_PECTMN | _0001_SCI_SIRMN_OVCTMN;
    SCI0->SCR03 &= ~_C000_SCI_RECEPTION_TRANSMISSION;
    SCI0->SCR03 |= _4000_SCI_RECEPTION;

#ifdef SPI11_BUFFER_EMPTY
    SCI0->SMR03 |= _0001_SCI_BUFFER_EMPTY; 
    if(sdr_prescale == 0) // SCK = fclk/2
    {
        DMAVEC->VEC[DMA_VECTOR_SPI11] = CTRL_DATA_SPI11;
        DMAVEC->CTRL[CTRL_DATA_SPI11].DMACR = (0 << CTRL_DMACR_SZ_Pos) | (1 << CTRL_DMACR_CHNE_Pos) |
                                              (0 << CTRL_DMACR_DAMOD_Pos) | (0 << CTRL_DMACR_SAMOD_Pos) |
                                              (0 << CTRL_DMACR_MODE_Pos);
        DMAVEC->CTRL[CTRL_DATA_SPI11].DMBLS = 1;
        DMAVEC->CTRL[CTRL_DATA_SPI11].DMACT = rx_num;
        DMAVEC->CTRL[CTRL_DATA_SPI11].DMRLD = rx_num;
        DMAVEC->CTRL[CTRL_DATA_SPI11].DMSAR = (uint32_t)&dummy;
        DMAVEC->CTRL[CTRL_DATA_SPI11].DMDAR = (uint32_t)&dummy;

        /* read receive data with DMA */
        DMAVEC->CTRL[CTRL_DATA_SPI11 + 1].DMACR = (0 << CTRL_DMACR_SZ_Pos) | (1 << CTRL_DMACR_CHNE_Pos) |
                                                  (1 << CTRL_DMACR_DAMOD_Pos) | (0 << CTRL_DMACR_SAMOD_Pos) |
                                                  (0 << CTRL_DMACR_MODE_Pos);
        DMAVEC->CTRL[CTRL_DATA_SPI11 + 1].DMBLS = 1;
        DMAVEC->CTRL[CTRL_DATA_SPI11 + 1].DMACT = rx_num;
        DMAVEC->CTRL[CTRL_DATA_SPI11 + 1].DMRLD = rx_num;
        DMAVEC->CTRL[CTRL_DATA_SPI11 + 1].DMSAR = (uint32_t)&SPI_RDDR;
        DMAVEC->CTRL[CTRL_DATA_SPI11 + 1].DMDAR = (uint32_t)rx_buf;

        /* dummy write to trigger next transfer */
        DMAVEC->CTRL[CTRL_DATA_SPI11 + 2].DMACR = (0 << CTRL_DMACR_SZ_Pos) | (0 << CTRL_DMACR_CHNE_Pos) |
                                                  (0 << CTRL_DMACR_DAMOD_Pos) | (0 << CTRL_DMACR_SAMOD_Pos) |
                                                  (0 << CTRL_DMACR_MODE_Pos);
        DMAVEC->CTRL[CTRL_DATA_SPI11 + 2].DMBLS = 1;
        DMAVEC->CTRL[CTRL_DATA_SPI11 + 2].DMACT = rx_num;
        DMAVEC->CTRL[CTRL_DATA_SPI11 + 2].DMRLD = rx_num;
        DMAVEC->CTRL[CTRL_DATA_SPI11 + 2].DMSAR = (uint32_t)&dummy;
        DMAVEC->CTRL[CTRL_DATA_SPI11 + 2].DMDAR = (uint32_t)&SPI_WRDR;

        /* init DMA registers */
        INT->IF[SPI11_IRQn].IFL = 0;
        CGC->PER1 |= CGC_PER1_DMAEN_Msk;
        DMA->DMABAR = DMAVEC_BASE;
        DMA->DMAEN1 |= (1 << DMA_VECTOR_SPI11 % 8);

        /* dummy write to trigger transfer start */
        SPI_WRDR = 0xFFU;
    }
    else 
    {
        /* read receive data with DMA */
        DMAVEC->VEC[DMA_VECTOR_SPI11] = CTRL_DATA_SPI11;
        DMAVEC->CTRL[CTRL_DATA_SPI11].DMACR = (0 << CTRL_DMACR_SZ_Pos) | (1 << CTRL_DMACR_CHNE_Pos) |
                                              (1 << CTRL_DMACR_DAMOD_Pos) | (0 << CTRL_DMACR_SAMOD_Pos) |
                                              (0 << CTRL_DMACR_MODE_Pos);
        DMAVEC->CTRL[CTRL_DATA_SPI11].DMBLS = 1;
        DMAVEC->CTRL[CTRL_DATA_SPI11].DMACT = rx_num;
        DMAVEC->CTRL[CTRL_DATA_SPI11].DMRLD = rx_num;
        DMAVEC->CTRL[CTRL_DATA_SPI11].DMSAR = (uint32_t)&SPI_RDDR;
        DMAVEC->CTRL[CTRL_DATA_SPI11].DMDAR = (uint32_t)rx_buf;

        /* dummy write to trigger next transfer */
        DMAVEC->CTRL[CTRL_DATA_SPI11 + 1].DMACR = (0 << CTRL_DMACR_SZ_Pos) | (0 << CTRL_DMACR_CHNE_Pos) |
                                                      (0 << CTRL_DMACR_DAMOD_Pos) | (0 << CTRL_DMACR_SAMOD_Pos) |
                                                      (0 << CTRL_DMACR_MODE_Pos);
        DMAVEC->CTRL[CTRL_DATA_SPI11 + 1].DMBLS = 1;
        DMAVEC->CTRL[CTRL_DATA_SPI11 + 1].DMACT = rx_num;
        DMAVEC->CTRL[CTRL_DATA_SPI11 + 1].DMRLD = rx_num;
        DMAVEC->CTRL[CTRL_DATA_SPI11 + 1].DMSAR = (uint32_t)&dummy;
        DMAVEC->CTRL[CTRL_DATA_SPI11 + 1].DMDAR = (uint32_t)&SPI_WRDR;

        /* init DMA registers */
        INT->IF[SPI11_IRQn].IFL = 0;
        CGC->PER1 |= CGC_PER1_DMAEN_Msk;
        DMA->DMABAR = DMAVEC_BASE;

        /* dummy write to trigger transfer start */
        SPI_WRDR = 0xFFU;
        DMA->DMAEN1 |= (1 << DMA_VECTOR_SPI11 % 8);
        SPI_WRDR = 0xFFU;
        INT->IF[SPI11_IRQn].IFL = 0;
    }

#else

    /* read receive data with DMA */
    DMAVEC->VEC[DMA_VECTOR_SPI11] = CTRL_DATA_SPI11;
    DMAVEC->CTRL[CTRL_DATA_SPI11].DMACR = (0 << CTRL_DMACR_SZ_Pos) | (1 << CTRL_DMACR_CHNE_Pos) |
                                          (1 << CTRL_DMACR_DAMOD_Pos) | (0 << CTRL_DMACR_SAMOD_Pos) |
                                          (0 << CTRL_DMACR_MODE_Pos);
    DMAVEC->CTRL[CTRL_DATA_SPI11].DMBLS = 1;
    DMAVEC->CTRL[CTRL_DATA_SPI11].DMACT = rx_num;
    DMAVEC->CTRL[CTRL_DATA_SPI11].DMRLD = rx_num;
    DMAVEC->CTRL[CTRL_DATA_SPI11].DMSAR = (uint32_t)&SPI_RDDR;
    DMAVEC->CTRL[CTRL_DATA_SPI11].DMDAR = (uint32_t)rx_buf;

    /* dummy write to trigger next transfer */
    DMAVEC->CTRL[CTRL_DATA_SPI11 + 1].DMACR = (0 << CTRL_DMACR_SZ_Pos) | (0 << CTRL_DMACR_CHNE_Pos) |
                                              (0 << CTRL_DMACR_DAMOD_Pos) | (0 << CTRL_DMACR_SAMOD_Pos) |
                                              (0 << CTRL_DMACR_MODE_Pos);
    DMAVEC->CTRL[CTRL_DATA_SPI11 + 1].DMBLS = 1;
    DMAVEC->CTRL[CTRL_DATA_SPI11 + 1].DMACT = rx_num;
    DMAVEC->CTRL[CTRL_DATA_SPI11 + 1].DMRLD = rx_num;
    DMAVEC->CTRL[CTRL_DATA_SPI11 + 1].DMSAR = (uint32_t)&dummy;
    DMAVEC->CTRL[CTRL_DATA_SPI11 + 1].DMDAR = (uint32_t)&SPI_WRDR;

    /* init DMA registers */
    INT->IF[SPI11_IRQn].IFL = 0;
    CGC->PER1 |= CGC_PER1_DMAEN_Msk;
    DMA->DMABAR = DMAVEC_BASE;

    /* dummy write to trigger transfer start */
    DMA->DMAEN1 |= (1 << DMA_VECTOR_SPI11 % 8);
    SPI_WRDR = 0xFFU;
#endif

    /* waiting DMA transfer end */
    while(INT->IF[SPI11_IRQn].IFL == 0x00);
    while(SPI_BUSY);
    SCI0->SMR03 &= ~_0001_SCI_BUFFER_EMPTY; 
    SCI0->SCR03 |=  _C000_SCI_RECEPTION_TRANSMISSION;
    INT->IF[SPI11_IRQn].IFL = 0;

}

__STATIC_INLINE void FlashSoftReset(void)
{
    /* Enable Reset Instruction */
    SPI_FLASH_CS_CLR();             /* chip select active */
    SPI_CPU_WRITE(ENABLE_RESET);
    SPI_FLASH_CS_SET();         /* chip select inactive */

    LOOP_WAIT(16);

    /* Reset Device Instruction */
    SPI_FLASH_CS_CLR();             /* chip select active */
    SPI_CPU_WRITE(RESET_DEVICE);
    SPI_FLASH_CS_SET();         /* chip select inactive */
}

__STATIC_INLINE uint8_t FlashReadStatus(status_t name)
{
    uint8_t inst;
    uint8_t tmp;

    SPI_FLASH_CS_CLR();             /* chip select active */
    if(name == STATUS_REG1)
        inst = READ_STATUS1;
    else
        inst = READ_STATUS2;
    SPI_CPU_WRITE(inst);
    tmp = SPI_CPU_READ();       /* get Status Register value */
    SPI_FLASH_CS_SET();         /* chip select inactive */

    return tmp;
}

__STATIC_INLINE void FlashWriteEnable(void)
{
    /* Write Enable Instruction */
    SPI_FLASH_CS_CLR();             /* chip select active */
    SPI_CPU_WRITE(WRITE_ENABLE);
    SPI_FLASH_CS_SET();         /* chip select inactive */
}

__STATIC_INLINE void FlashWriteStatus(status_t name, uint8_t data)
{
    uint8_t inst;

    /* Write enable instruction */
    FlashWriteEnable();     

    LOOP_WAIT(16);

    /* Write Status Register Instruction */
    SPI_FLASH_CS_CLR();             /* chip select active */
    if(name == STATUS_REG1)
        inst = WRITE_STATUS1;
    else
        inst = WRITE_STATUS2;
    SPI_CPU_WRITE(inst);
    SPI_CPU_WRITE(data);
    SPI_FLASH_CS_SET();         /* chip select inactive */
}

__STATIC_INLINE void FlashEraseSector(uint32_t adr)
{
    /* Write enable instruction */
    FlashWriteEnable();     

    LOOP_WAIT(16);

    /* Sector Erase Instruction */
    SPI_FLASH_CS_CLR();             /* chip select active */
    SPI_CPU_WRITE(SECTOR_ERASE);
    SPI_CPU_WRITE(BYTE_FIELD(adr, 2)); // Address [23:16] 
    SPI_CPU_WRITE(BYTE_FIELD(adr, 1)); // Address [15:08] 
    SPI_CPU_WRITE(BYTE_FIELD(adr, 0)); // Address [07:00] 
    SPI_FLASH_CS_SET();         /* chip select inactive */

    LOOP_WAIT(16);

    /* polling busy flag */
    SPI_FLASH_CS_CLR();             /* chip select active */
    SPI_CPU_WRITE(READ_STATUS1);
    while(SPI_CPU_READ() & BUSY_Msk);  
    SPI_FLASH_CS_SET();         /* chip select inactive */
}

__STATIC_INLINE void FlashEraseBlock(uint32_t adr)
{
    /* Write enable instruction */
    FlashWriteEnable();     

    LOOP_WAIT(16);

    /* Block Erase Instruction */
    SPI_FLASH_CS_CLR();             /* chip select active */
    SPI_CPU_WRITE(BLOCK_ERASE);
    SPI_CPU_WRITE(BYTE_FIELD(adr, 2)); // Address [23:16] 
    SPI_CPU_WRITE(BYTE_FIELD(adr, 1)); // Address [15:08] 
    SPI_CPU_WRITE(BYTE_FIELD(adr, 0)); // Address [07:00] 
    SPI_FLASH_CS_SET();         /* chip select inactive */

    LOOP_WAIT(16);

    /* polling busy flag */
    SPI_FLASH_CS_CLR();             /* chip select active */
    SPI_CPU_WRITE(READ_STATUS1);
    while(SPI_CPU_READ() & BUSY_Msk);  
    SPI_FLASH_CS_SET();         /* chip select inactive */
}

__STATIC_INLINE void FlashEraseChip(void)
{
    /* Write enable instruction */
    FlashWriteEnable();     

    /* Block Erase Instruction */
    SPI_FLASH_CS_CLR();             /* chip select active */
    SPI_CPU_WRITE(CHIP_ERASE);
    SPI_FLASH_CS_SET();         /* chip select inactive */

    LOOP_WAIT(16);

    /* polling busy flag */
    SPI_FLASH_CS_CLR();             /* chip select active */
    SPI_CPU_WRITE(READ_STATUS1);
    while(SPI_CPU_READ() & BUSY_Msk);  
    SPI_FLASH_CS_SET();         /* chip select inactive */
}

__STATIC_INLINE void FlashProgramPage(uint32_t adr, uint32_t sz, uint8_t *buf)
{
    /* Write enable instruction */
    FlashWriteEnable();     

    LOOP_WAIT(16);

    /* Page Program Instruction */
    SPI_FLASH_CS_CLR();             /* chip select active */
    SPI_CPU_WRITE(PAGE_WRITE);
    SPI_CPU_WRITE(BYTE_FIELD(adr, 2)); // Address [23:16] 
    SPI_CPU_WRITE(BYTE_FIELD(adr, 1)); // Address [15:08] 
    SPI_CPU_WRITE(BYTE_FIELD(adr, 0)); // Address [07:00] 
#ifdef SPI11_WITH_DMA
    SPI_DMA_WRITE(buf, sz);
#else
    while(sz--)
    {
        SPI_CPU_WRITE(*buf++); // Write Data Byte
    }
#endif
    SPI_FLASH_CS_SET();         /* chip select inactive */

    LOOP_WAIT(16);

    /* polling busy flag */
    SPI_FLASH_CS_CLR();             /* chip select active */
    SPI_CPU_WRITE(READ_STATUS1);
    while(SPI_CPU_READ() & BUSY_Msk);  
    SPI_FLASH_CS_SET();         /* chip select inactive */
}

__STATIC_INLINE void FlashReadData(uint32_t adr, uint32_t sz, uint8_t *buf)
{
    volatile uint8_t tmp;
    /* Fast Read Instruction */
    SPI_FLASH_CS_CLR();             /* chip select active */
    SPI_CPU_WRITE(READ_DATA);
    SPI_CPU_WRITE(BYTE_FIELD(adr, 2)); // Address [23:16] 
    SPI_CPU_WRITE(BYTE_FIELD(adr, 1)); // Address [15:08] 
    SPI_CPU_WRITE(BYTE_FIELD(adr, 0)); // Address [07:00] 
#ifdef SPI11_WITH_DMA
    SPI_DMA_READ(buf, sz);
#else
    while(sz--)
    {
        tmp = SPI_CPU_READ(); // Read Data Byte 
        *buf++ = tmp;
    }
#endif
    SPI_FLASH_CS_SET();         /* chip select inactive */
}

__STATIC_INLINE void FlashFastRead(uint32_t adr, uint32_t sz, uint8_t *buf)
{
    volatile uint8_t tmp;
    /* Fast Read Instruction */
    SPI_FLASH_CS_CLR();             /* chip select active */
    SPI_CPU_WRITE(FAST_READ);
    SPI_CPU_WRITE(BYTE_FIELD(adr, 2)); // Address [23:16] 
    SPI_CPU_WRITE(BYTE_FIELD(adr, 1)); // Address [15:08] 
    SPI_CPU_WRITE(BYTE_FIELD(adr, 0)); // Address [07:00] 
    SPI_CPU_WRITE(0xFFU);       /* 8 cycles dummy clocks */
#ifdef SPI11_WITH_DMA
    SPI_DMA_READ(buf, sz);
#else
    while(sz--)
    {
        tmp = SPI_CPU_READ(); // Read Data Byte 
        *buf++ = tmp;
    }
#endif
    SPI_FLASH_CS_SET();         /* chip select inactive */
}
#endif
